package com.rajaev.dtu.tractor.app.scheduleTask;

import cn.hutool.core.thread.NamedThreadFactory;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCursor;
import com.rajaev.dtu.tractor.app.service.BatteryInspectService;
import com.rajaev.dtu.tractor.app.service.FaultService;
import com.rajaev.dtu.tractor.domain.entity.BatteryInspectTaskPo;
import com.rajaev.dtu.tractor.infrastructure.base.common.Constants;
import com.rajaev.dtu.tractor.infrastructure.helper.MongoDbUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.IteratorUtils;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;

import static com.mongodb.client.model.Filters.and;
import static com.mongodb.client.model.Filters.eq;

/**
 * @Created with IDEA
 * @author: tianjie
 * @Date:2019/4/11
 * @Time:11:37
 */
@Component
@EnableScheduling
@Slf4j
public class BatteryInspectScheduleTask {

    public static ThreadPoolExecutor threadPoolExecutor;


    @Autowired
    private MongoDbUtils mongoDbUtils;

    @Autowired
    private BatteryInspectService batteryInspectService;

    @Autowired
    private FaultService faultService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisLockRegistry redisLockRegistry;

    /**
     * 初始化线程池
     */
    @PostConstruct
    public void initThreadPool() {

        if (threadPoolExecutor != null) {
            return;
        }
        BlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue(1024);
        ThreadFactory threadFactory = new NamedThreadFactory("battery-inspect-thread",false);

        threadPoolExecutor = new ThreadPoolExecutor(2, Runtime.getRuntime().availableProcessors(), 10, TimeUnit.SECONDS, blockingQueue, threadFactory) {
            @Override
            protected void beforeExecute(Thread t, Runnable r) {
                log.info("start inspect vin : {}", t.getName(), t.getId());
            }

            @Override
            protected void afterExecute(Runnable r, Throwable t) {
            }

            @Override
            protected void terminated() {
                log.info("线程池关闭");
            }
        };
    }


    @Scheduled(cron = "0 0 0/2 * * ?")
    public void doInspect() {

        Lock lock = redisLockRegistry.obtain("bms-inspect-task");
        if (lock.tryLock()) {
            try {
                List<BatteryInspectTaskPo> unCompleteTaskList = batteryInspectService.selectNoCompleteTask();
                unCompleteTaskList.forEach(batteryInspectTaskPo -> {
                    FindIterable findIterable = mongoDbUtils.getDatabase()

                            .getCollection(Constants.batteryInspectTaskCollectionName)
                            .find(and(eq("taskId", batteryInspectTaskPo.getTaskId())
                                    , eq("state", 0)));
                    MongoCursor cursor = findIterable.iterator();
                    List<Document> list = IteratorUtils.toList(cursor);
                    CompletionService<Boolean> completionService = new ExecutorCompletionService(threadPoolExecutor);

                    for (Document document : list) {
                        String vin = (String) document.get("vin");
                        BatterInspectCaller runner = new BatterInspectCaller(batteryInspectTaskPo.getTaskId(), vin);
                        completionService.submit(runner);
                    }
                    AtomicInteger count = new AtomicInteger();
                    for (int i = 0; i < list.size(); i++) {
                        try {
                            if (completionService.take().get()) {
                                count.addAndGet(1);
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } catch (ExecutionException e) {
                            e.printStackTrace();
                        }
                    }

                    log.info("成功个数：" + count);

                });
            } finally {
                lock.unlock();
            }

        }else {
            log.info("执行巡检任务加锁不成功。");
        }
    }


}
